/*
 * ----------------------------------------------------------------------- Copyright 2012 - Alistair
 * Rutherford - www.netthreads.co.uk
 * -----------------------------------------------------------------------
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package com.garrigou.spaceship.layer;

import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.utils.Pool;
import com.garrigou.spaceship.action.ActionCallBack;
import com.garrigou.spaceship.action.CallBackDelayAction;
import com.garrigou.spaceship.constants.ActorEvents;
import com.garrigou.spaceship.director.Director;
import com.garrigou.spaceship.event.ActorEvent;
import com.garrigou.spaceship.event.ActorEventObserver;
import com.garrigou.spaceship.scenes.Layer;
import com.garrigou.spaceship.sprite.AsteroidSprite;

/**
 * Scene layer.
 * 
 */
public class AsteroidLayer extends Layer implements ActorEventObserver, ActionCallBack
{
    private static final int     INITIAL_SPRITE_CAPACITY = 20;

    public static final float    FRAME_DURATION          = 0.2f; // Animation frame duration.
    private static final float   CONTROL_INTERVAL        = 1.75f; // How often to start.
    static TextureAtlas          textureAtlas;
    // -------------------------------------------------------------------
    // Sprite pool.
    // -------------------------------------------------------------------
    private Pool<AsteroidSprite> pool                    = new Pool<AsteroidSprite>(
                                                                 INITIAL_SPRITE_CAPACITY)
                                                         {
                                                             @Override
                                                             protected AsteroidSprite newObject()
                                                             {
                                                                 // load all the regions of the asteroid in
                                                                 // the image atlas
                                                                 TextureRegion region = textureAtlas
                                                                         .findRegion("level-screen/asteroide");
                                                                 AsteroidSprite sprite = new AsteroidSprite(
                                                                         region,
                                                                         1,
                                                                         1,
                                                                         AsteroidLayer.FRAME_DURATION);

                                                                 return sprite;
                                                             }
                                                         };

    // Director of the action.
    private Director             director;

    /**
     * Create asteroid layer.
     * 
     * @param stage
     */
    public AsteroidLayer(float width, float height, TextureAtlas atlas)
    {
        setSize(width, height);
        this.textureAtlas = atlas;

        // The one and only director.
        director = Director.instance();

        buildActions();
    }

    /**
     * Called when layer is part of visible view but not yet displayed.
     * 
     */
    @Override
    public void enter()
    {
        // Add this as an event observer.
        director.registerEventHandler(this);
    }

    /**
     * Called when layer is no longer part of visible view.
     * 
     */
    @Override
    public void exit()
    {
        cleanup();

        // Remove this as an event observer.
        director.deregisterEventHandler(this);
    }

    /**
     * Pooled layers need cleanup view elements.
     * 
     */
    private void cleanup()
    {
        // Array<Actor> list = this.getChildren();
        //
        // for (Actor actor : list)
        // {
        // actor.markToRemove(true);
        // }
    }

    /**
     * Create timer action to start layer elements.
     * 
     */
    private void buildActions()
    {
        CallBackDelayAction callBackDelay = CallBackDelayAction.$(-1, CONTROL_INTERVAL, this);

        addAction(callBackDelay);
    }

    /**
     * Every delay duration make a decision about what to do next.
     * 
     */
    @Override
    public void onCallBack()
    {
        // Launch an asteroid.
        this.director.sendEvent(ActorEvents.EVENT_START_ASTEROID, this);
    }

    /**
     * Remove item from layer then free it from pool.
     * 
     * @return
     */
    @Override
    public boolean removeActor(Actor actor)
    {
        super.removeActor(actor);

        AsteroidSprite sprite = (AsteroidSprite) actor;
        sprite.clearActions();

        pool.free(sprite);

        return true;
    }

    /**
     * Handle events.
     * 
     */
    @Override
    public boolean handleEvent(ActorEvent event)
    {
        boolean handled = false;

        switch (event.getId())
        {
            case ActorEvents.EVENT_START_ASTEROID:
                handleStartAsteroid();
                handled = true;
            break;
            case ActorEvents.EVENT_COLLISION_ASTEROID_PULSE:
                handlePulseCollision(event.getActor());
                handled = true;
            break;
            case ActorEvents.EVENT_END_ASTEROID:
                handleEndAsteroid(event.getActor());
                handled = true;
            break;
            default:
            break;
        }

        return handled;
    }

    /**
     * Launch a sprite from pool (if one available).
     * 
     */
    private void handleStartAsteroid()
    {
        // Get free sprite from pool.
        AsteroidSprite sprite = pool.obtain();

        // Add to view.
        addActor(sprite);

        // DO THIS AFTER ADDING TO VIEW.
        sprite.run();
    }

    /**
     * Handle pulse hitting asteroid.
     * 
     * @param actor
     */
    private void handlePulseCollision(Actor actor)
    {
        // Run explosion sprite
        this.director.sendEvent(ActorEvents.EVENT_START_ASTEROID_EXPLOSION, actor);

        handleEndAsteroid(actor);

        // Update score.
        // AppStats.instance().incScore();
    }

    /**
     * Handle controller events.
     * 
     * @param event
     *        The actor event.
     * 
     * @return True if handled.
     */
    private void handleEndAsteroid(Actor source)
    {
        removeActor(source);
//        source.remove();
        // This will trigger a "removeActor" call.
        // The 'finish' method will be called for all associated actions. That's where you would put
        // actions back into
        // pool.
        // source.markToRemove(true);
    }

}
